<!DOCTYPE html>
<html>
  <head>
    <!--Import Google Icon Font-->
    <link type="text/css" rel="stylesheet" href="css/material-icons.css"/>
    <!--Import materialize.css-->
    <link type="text/css" rel="stylesheet" href="css/materialize.min.css"  media="screen,projection"/>
    <title>Monitor Instance Status</title>

    <!--Let browser know website is optimized for mobile-->
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <style>
    nav.clean{
        background: none;
        box-shadow: none;
    }

    .breadcrumb:before {
        color: rgba(0,0,0,0.7);
    }

    .breadcrumb, .breadcrumb:last-child {
       color: rgba(0,0,0,1);
    }
    </style>

  </head>
  <body>

  <div class="container">
    <div class="section">
      <nav class="clean">
         <div class="nav-wrapper">
           <div class="col s12" id="breadcrumb-path">
             <a href="dashboard.html" class="breadcrumb" id="zone-caption"></a>
             <a href="pool_status.html" class="breadcrumb" id="pool-caption"></a>
            </div>
        </div>
      </nav>
      <div class="divider"></div>
    </div>
    <div class="section">
      <div class="row">
        <div class="col m6 s12">
          <div class="card small">
            <div class="card-content">
              <span class="card-title" id="instance-name"><i class="material-icons blue-grey-text darken-2">cloud_queue</i></span>
              <table class="striped">
                <tbody>
                  <tr>
                    <td id="core-caption"></td>
                    <td id="instance-cores"></td>
                    <td id="internal-caption"></td>
                    <td id="instance-internal"></td>
                  </tr>
                  <tr>
                    <td id="memory-caption"></td>
                    <td id="instance-memory"></td>
                    <td id="external-caption"></td>
                    <td id="instance-external"></td>
                  </tr>
                  <tr>
                    <td id="disk-caption"></td>
                    <td id="instance-disk"></td>
                    <td></td>
                    <td id="instance-icons">
                    </td>
                  </tr>
                </tbody>
              </table>
            </div>
            <div class="card-action" id="instance-actions">
            </div>
          </div>
        </div>
        <div class="col m3 s6">
          <div class="card small">
            <div class="card-content">
              <span class="card-title" id="core-usage-caption"><i class="material-icons blue-grey-text">memory</i></span>
              <div>
                <canvas id="cpu_canvas" height="250px"></canvas>
              </div>
            </div>
          </div>
        </div>
        <div class="col m3 s6">
          <div class="card small">
            <div class="card-content">
              <span class="card-title" id="memory-usage-caption"><i class="material-icons blue-grey-text">sd_card</i></span>
              <div>
                <canvas id="memory_canvas" height="250px"></canvas>
              </div>
            </div>
          </div>
        </div>

      </div>
      <div class="row">
        <div class="col m4 s6">
          <div class="card small">
            <div class="card-content">
              <span class="card-title" id="disk-usage-caption"><i class="material-icons blue-grey-text">storage</i></span>
              <div>
                <canvas id="disk_canvas" height="160px"></canvas>
              </div>
            </div>
          </div>
        </div>

        <div class="col m8 s12">
          <div class="card small">
            <div class="card-content">
              <span class="card-title" id="io-caption"><i class="material-icons blue-grey-text">show_chart</i></span>
              <div>
                <canvas id="io_canvas" height="80px"></canvas>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
    <div class="modal" id="delete_modal">
        <div class="modal-content">
            <h4>Delete Confirm</h4>
            <p id="delete_confirm_content"></p>
        </div>
        <div class="modal-footer">
            <a href="#" class="modal-close waves-effect waves-green btn-flat">No</a>
            <a href="#" class="modal-close waves-effect waves-green btn-flat" id="delete_confirm_link">Yes</a>
        </div>
    </div>
    <div class="modal" id="media_modal">
        <!--hide model -->
        <div class="modal-content">
            <h4>Start guest with media</h4>
            <div class="row">
              <div class="input-field col m4">
                  <select name="media" id="media_options">
                  </select>
                  <label>Choose Media</label>
              </div>
            </div>
        </div>
        <div class="modal-footer">
            <a href="#" class="modal-close waves-effect waves-green btn-flat">No</a>
            <a href="#" class="modal-close waves-effect waves-green btn-flat" id="media_confirm_link">Yes</a>
        </div>
    </div>
    <div class="modal" id="insert_modal">
        <!--hide model -->
        <div class="modal-content">
            <h4>Insert media into instance</h4>
            <div class="row">
              <div class="input-field col m4">
                  <select name="media" id="insert_options">
                  </select>
                  <label>Choose Media</label>
              </div>
            </div>
        </div>
        <div class="modal-footer">
            <a href="#" class="modal-close waves-effect waves-green btn-flat">No</a>
            <a href="#" class="modal-close waves-effect waves-green btn-flat" id="insert_confirm_link">Yes</a>
        </div>
    </div>
    <div class="modal" id="eject_modal">
        <!--hide model -->
        <div class="modal-content">
            <h4>Eject media from instance</h4>
            <p id="eject_confirm_content"></p>
        </div>
        <div class="modal-footer">
            <a href="#" class="modal-close waves-effect waves-green btn-flat">No</a>
            <a href="#" class="modal-close waves-effect waves-green btn-flat" id="eject_confirm_link">Yes</a>
        </div>
    </div>
  </div>

  <!--JavaScript at end of body for optimized loading-->
  <script type="text/javascript" src="js/materialize.min.js"></script>
  <script type="text/javascript" src="js/jquery-3.3.1.min.js"></script>
  <script type="text/javascript" src="js/Chart.bundle.min.js"></script>
  <script type="text/javascript" src="js/nano.js"></script>
  <script>
    N.ValidateSession();
    var texts = N.GetTexts();
    $('#zone-caption').text(texts.get(N.TagZone));
    $('#pool-caption').text(texts.get(N.TagComputePool));
    $('.modal-footer > a:first-child').text(texts.get(N.TagCancel));
    $('.modal-footer > a:last-child').text(texts.get(N.TagConfirm));

    $('#core-caption').text(texts.get(N.TagCore));
    $('#internal-caption').text(texts.get(N.TagInternalAddress));
    $('#memory-caption').text(texts.get(N.TagMemory));
    $('#external-caption').text(texts.get(N.TagExternalAddress));
    $('#disk-caption').text(texts.get(N.TagDisk));

    $('#core-usage-caption').text(texts.get(N.TagCoreUsage));
    $('#memory-usage-caption').text(texts.get(N.TagMemoryUsage));
    $('#disk-usage-caption').text(texts.get(N.TagDisk));
    $('#io-caption').text(texts.get(N.TagIOMeter));

    M.AutoInit();
    var poolName;
    var cellName;
    var instanceID;
    function parseQueryString(){
      var url = window.location.search;
      var queryString = url.substring( url.indexOf('?') + 1 );
      if (0 === queryString.length){
        M.toast({html: 'no query string available', outDuration: 1500});
        return false;
      }
      var values = queryString.split("&");
      var params = new Map();
      values.forEach((value) => {
        var p = value.split('=');
        params.set(p[0], p[1]);
      });
      if (0 == params.length){
        M.toast({html: 'invalid query string', outDuration: 1500});
        return false;
      }
      if (!params.has('pool')){
        M.toast({html: 'Must specify pool name', outDuration: 1500});
        return false;
      }
      poolName = params.get('pool');
      if (params.has('cell')){
        cellName = params.get('cell');
      }
      if (!params.has('instance')){
        M.toast({html: 'Must specify instance', outDuration: 1500});
        return false;
      }
      instanceID = params.get('instance');
      return true;
    }

    var diskChart = new Chart( $("#disk_canvas"), {
      type: "doughnut",
      data: {
        labels: [texts.get(N.TagAvailable), texts.get(N.TagUsed)],
        datasets: [
          {
            backgroundColor: ['#bbdefb', '#2196f3'],
          }
        ],
      },
      options: {
        cutoutPercentage: 70,
        legend: {
          display: false,
        }
      }
    });
    //cpu canvas
    var cpuChart = new Chart($("#cpu_canvas"), {
        type: "bar",
        data: {
          labels: ["10", "8", "6", "4", "2", "0"],
          datasets: [
            {
              label: texts.get(N.TagUsed),
              stack: 'Stack 0',
              backgroundColor: '#66bb6a',
            },
            {
              label: texts.get(N.TagAvailable),
              stack: 'Stack 0',
              backgroundColor: '#e8f5e9',
            }
          ]
        },
        options: {
          legend: {
            display: false,
          },
          scales: {
            xAxes: [{
              display: false
            }],
            yAxes: [{
                stacked: true
            }]
          }
        }
    });
    //memory canvas
    var memoryChart = new Chart( $("#memory_canvas"), {
        type: "bar",
        data: {
          labels: ["10", "8", "6", "4", "2", "0"],
          datasets: [
            {
              label: texts.get(N.TagUsed),
              stack: 'Stack 0',
              backgroundColor: '#42a5f5',
            },
            {
              label: texts.get(N.TagAvailable),
              stack: 'Stack 0',
              backgroundColor: '#e3f2fd',
            }
          ]
        },
        options: {
          legend: {
            display: false,
          },
          scales: {
            xAxes: [{
              display: false
            }],
            yAxes: [{
                stacked: true
            }]
          }
        }
    });

    //io
    var ioChart = new Chart( $("#io_canvas"), {
        type: "bar",
        data: {
          labels: ["16", "14", "12", "10", "8", "6", "4", "2", "0"],
          datasets: [
            {
              label: texts.get(N.TagRead),
              backgroundColor: '#90caf9',
            },
            {
              label: texts.get(N.TagWrite),
              backgroundColor: '#b0bec5',
            },
            {
              label: texts.get(N.TagReceive),
              backgroundColor: '#b39ddb',
            },
            {
              label: texts.get(N.TagSend),
              backgroundColor: '#9fa8da',
            },
          ]
        },
        options: {
          legend: {
            display: false,
          },
          scales: {
            xAxes: [{
              display: true,
              scaleLabel: {
                display: true,
                labelString: 'Past Seconds'
              }
            }],
            yAxes: [{
              display: true,
              scaleLabel: {
                display: true,
                labelString: 'MBytes/s'
              }
            }]
          }
        }
    });
    function initialCharts(){
      diskChart.data.datasets[0].data = [0, 0];
      var cpuChartDataCount = 6;
      for(var i = 0; i < cpuChartDataCount;i++){
        cpuChart.data.datasets[0].data.push(0);
        cpuChart.data.datasets[1].data.push(0);
      }
      cpuChart.options.scales.yAxes[0].ticks = {
          min: 0,
          max: 100,
          stepSize: 20
      };
      for(var i = 0; i < 6;i++){
        memoryChart.data.datasets[0].data.push(0);
        memoryChart.data.datasets[1].data.push(0);
      }
      memoryChart.options.scales.yAxes[0].ticks = {
          min: 0,
          max: 100,
          stepSize: 20
      };

      for(var i = 0; i < 9;i++){
        ioChart.data.datasets.forEach((dataset) => {
          dataset.data.push(0);
        });
      }
      ioChart.options.scales.yAxes[0].ticks = {
          min: 0,
          max: 10,
          stepSize: 2
      };
      diskChart.update();
      cpuChart.update();
      memoryChart.update();
      ioChart.update();
    }

    var running, autostart, mediaAttached;
    function updateDashboard(){
      $.getJSON("/instances/" + instanceID, function(result){
        if (0 != result['error_code']) {
            M.toast({html: 'update dashboard fail:' + result['message']});
            return;
        }
        //success
        var status = result['data'];
        var instanceName = status['name'];
        $('#instance-name').text(status['name']).prepend($('<i>').addClass('material-icons blue-grey-text darken-2').text('cloud_queue'));
        $('#instance-cores').text(status['cores']);

        var operators = $('#instance-actions');

        if (running != status['running']){
          running = status['running'];
          //change
          $('#instance-icons').empty();
          operators.empty();
          if (running){
            $('#instance-icons').prepend(
              $('<i>').addClass('material-icons green-text darken-2 tooltipped').attr('data-position', 'top').attr('data-tooltip', texts.get(N.TagRunning)).text('play_arrow')
            );
            operators.append(
              $('<a>').attr('href', 'instance_control.html?instance=' + instanceID).addClass('blue-grey-text tooltipped').attr('data-position', 'top').
                attr('data-tooltip',  texts.get(N.TagRemoteControl)).attr('target', '_blank').append(
                  $('<i>').addClass('material-icons').text('desktop_windows')
                )
            );
            operators.append(
              $('<a>').attr('href', '#').addClass('blue-grey-text tooltipped').attr('data-position', 'top').
                attr('data-tooltip',  texts.get(N.TagStop)).append(
                  $('<i>').addClass('material-icons').text('power_settings_new')
                ).click(function(){
                  N.StopInstance(instanceName, instanceID);
                })
            );
            operators.append(
              $('<a>').attr('href', '#').addClass('blue-grey-text tooltipped').attr('data-position', 'top').
                attr('data-tooltip',  texts.get(N.TagForceStop)).append(
                  $('<i>').addClass('material-icons').text('power')
                ).click(function(){
                  N.ForceStopInstance(instanceName, instanceID);
                })
            );
            operators.append(
              $('<a>').attr('href', '#').addClass('blue-grey-text tooltipped').attr('data-position', 'top').
                attr('data-tooltip',  texts.get(N.TagReboot)).append(
                  $('<i>').addClass('material-icons').text('rotate_right')
                ).click(function(){
                  N.RestartInstance(instanceName, instanceID);
                })
            );
            operators.append(
              $('<a>').attr('href', '#').addClass('blue-grey-text tooltipped').attr('data-position', 'top').
                attr('data-tooltip',  texts.get(N.TagForceReboot)).append(
                  $('<i>').addClass('material-icons').text('refresh')
                ).click(function(){
                  N.ResetInstance(instanceName, instanceID);
                })
            );
            mediaAttached = status['media_attached'];
            updateMediaStatus(instanceID, instanceName, running, mediaAttached, operators);
          }else{
            $('#instance-icons').prepend(
              $('<i>').addClass('material-icons red-text darken-2 tooltipped').attr('data-position', 'top').attr('data-tooltip',  texts.get(N.TagStopped)).text('stop')
            );
            operators.append(
              $('<a>').attr('href', '#').addClass('blue-grey-text tooltipped').attr('data-position', 'top').
                attr('data-tooltip',  texts.get(N.TagStart)).append(
                  $('<i>').addClass('material-icons').text('play_arrow')
                ).click(function(){
                  N.StartInstance(instanceName, instanceID);
                })
            );
            operators.append(
              $('<a>').attr('href', '#').addClass('blue-grey-text tooltipped').attr('data-position', 'top').
                attr('data-tooltip',  texts.get(N.TagStartWithMedia)).attr('onclick', 'selectMedia("' + instanceName + '","' + instanceID + '")').append(
                  $('<i>').addClass('material-icons').text('play_circle_outline')
                )
            );
            operators.append(
              $('<a>').attr('href', 'snapshots.html?pool=' + poolName + '&instance=' + instanceID).addClass('blue-grey-text tooltipped').attr('data-position', 'top').
                attr('data-tooltip',  texts.get(N.TagSnapshot)).attr('target', '_blank').append(
                  $('<i>').addClass('material-icons').text('photo_camera')
                )
            );
            operators.append(
              $('<a>').attr('href', 'build_image.html?instance=' + instanceID).addClass('blue-grey-text tooltipped').attr('data-position', 'top').
                attr('data-tooltip',  texts.get(N.TagBuildDiskImage)).attr('target', '_blank').append(
                  $('<i>').addClass('material-icons').text('cloud_upload')
                )
            );
          }
        }
        if (autostart != status['auto_start']){
          autostart = status['auto_start'];
          if (autostart){
            $('#instance-icons').append(
              $('<i>').addClass('material-icons light-blue-text tooltipped').attr('data-position', 'top').attr('data-tooltip', texts.get(N.TagAutoStart) + ' ' + texts.get(N.TagEnable)).text('all_inclusive').attr('id', 'autostart-icon')
            );
          }else{
            $('i#autostart-icon').remove();
          }
        }
        if (mediaAttached != status['media_attached']){
          //attach status changed
          mediaAttached = status['media_attached'];
          updateMediaStatus(instanceID, instanceName, running, mediaAttached, operators);
        }
        //Address
        if (status['internal']){
          var internal = status['internal'];
          if (internal['network_address']){
            $('#instance-internal').text(internal['network_address']);
          }
        }
        if (status['external']){
          var external = status['external'];
          if (external['network_address']){
            $('#instance-external').text(external['network_address']);
          }
        }

        var gib = 1 << 30;
        var availableDisk = Math.floor(status['disk_available'] * 100 / gib) / 100;
        var usedDisk = Math.floor((status['total_disk'] - status['disk_available']) * 100 / gib) / 100;
        diskChart.data.datasets[0].data = [availableDisk, usedDisk];
        var disks = new Array();
        status['disks'].forEach((disk) => {
          disks.push(disk / gib);
        });
        $('#instance-disk').text(disks.join(' / ') + ' GiB');


        //cpu
        cpuChart.data.datasets[0].data.shift();
        cpuChart.data.datasets[0].data.push(Math.floor(status['cpu_usage'] * status['cores'])/100);
        cpuChart.data.datasets[1].data.shift();
        cpuChart.data.datasets[1].data.push(Math.floor(( 100 - status['cpu_usage']) * status['cores'])/100);
        cpuChart.options.scales.yAxes[0].ticks = {
            max: status['cores'],
            stepSize: status['cores'] / 4
        };
        var used_memory = Math.floor((status['memory'] - status['memory_available']) * 100 / gib) / 100;
        var max_memory = Math.round(status['memory']  / gib) ;
        var available_memory = Math.floor(status['memory_available'] * 100 / gib) / 100;
        //memory
        memoryChart.data.datasets[0].data.shift();
        memoryChart.data.datasets[0].data.push(used_memory);
        memoryChart.data.datasets[1].data.shift();
        memoryChart.data.datasets[1].data.push(available_memory);
        memoryChart.options.scales.yAxes[0].ticks = {
            max: max_memory,
            stepSize: max_memory / 4
        };
        var mib = 1 << 20;
        $('#instance-memory').text(status['memory']/mib + ' MiB');

        var speed = [Math.floor(status['bytes_read'] * 100 / mib) / 100, Math.floor(status['bytes_written'] * 100 / mib) / 100,
            Math.floor(status['bytes_received'] * 100 / mib) / 100, Math.floor(status['bytes_sent'] * 100 / mib) / 100 ]

        for(var i = 0; i < 4 ; i++)    {
          ioChart.data.datasets[i].data.shift();
          ioChart.data.datasets[i].data.push(speed[i]);
        }
        diskChart.update();
        cpuChart.update();
        memoryChart.update();
        ioChart.update();
        $('.material-tooltip').remove();
        M.Tooltip.init($('.tooltipped'));
      });
    }

    function updateMediaStatus(instanceID, instanceName, running, attached, operators){
      const iconID = "media-icon";
      const ejectID = "eject-btn";
      const insertID = "insert-btn";
      if (attached){
        $('#instance-icons').append(
          $('<i>').addClass('material-icons blue-grey-text tooltipped').attr('data-position', 'top')
            .attr('data-tooltip',  texts.get(N.TagMediaAttached)).text('album').attr('id', iconID)
        );
        if(running){
          $('#' + insertID).remove();
          operators.append(
            $('<a>').attr('href', '#').addClass('blue-grey-text tooltipped').attr('data-position', 'top').attr('id', ejectID).
              attr('data-tooltip',  texts.get(N.TagEjectMedia)).attr('onclick', 'confirmEject("' + instanceName + '","' + instanceID + '")').append(
                $('<i>').addClass('material-icons').text('eject')
              )
          );
        }
      }else{
        $('#' + iconID).remove();
        if(running){
          $('#' + ejectID).remove();
          operators.append(
            $('<a>').attr('href', '#').addClass('blue-grey-text tooltipped').attr('data-position', 'top').attr('id', insertID).
              attr('data-tooltip',  texts.get(N.TagInsertMedia)).attr('onclick', 'selectInsertMedia("' + instanceName + '","' + instanceID + '")').append(
                $('<i>').addClass('material-icons').text('arrow_drop_down')
              )
          );
        }
      }
    }

    function selectMedia(name, id){
      $('#media_confirm_link').attr('onclick', 'startWithMedia("' + name + '", "' + id +'")');
      var queryURL = '/media_image_search/?session=' + N.GetSessionID();
      $.getJSON(
        queryURL,
        function(result){
          if (0 != result['error_code']) {
              M.toast({html: 'fetch media fail: ' + result['message'], outDuration: 600});
              return;
          }
          if (!result['data']){
            M.toast({html: 'no media image available', outDuration: 600});
            return;
          }
          $('#media_options').empty();
          result['data'].forEach((media)=>{
            $('#media_options').append(
              $('<option>').attr('value', media['id']).text(media['name'])
            );
          });
          M.FormSelect.init($('#media_options'));
          var instance = M.Modal.getInstance($('#media_modal'));
          instance.open();
        }
      )
    }

    function startWithMedia(name, id){
      var media = $('#media_options').val();
      var mediaName = $('#media_options :selected').text();
      $.post(
        '/instances/' + id,
        JSON.stringify({
          "from_media": true,
          "source": media
        }),
        function(result){
          if (0 != result['error_code']) {
              M.toast({html: 'start instance fail: ' + result['message'], outDuration: 1000});
              return;
          }
          M.toast({html: 'instance "' + name + '" started with media ' + mediaName});
          N.WriteOperateLog('start instance ' + name + ' / ' + id + ' with media ' + mediaName);
        },
        "json"
      );
    }

    //insert media
    function selectInsertMedia(name, id){
      $('#insert_confirm_link').attr('onclick', 'insertMedia("' + name + '", "' + id +'")');
      var queryURL = '/media_image_search/?session=' + N.GetSessionID();
      $.getJSON(
        queryURL,
        function(result){
          if (0 != result['error_code']) {
              M.toast({html: 'fetch media fail: ' + result['message'], outDuration: 600});
              return;
          }
          $('#insert_options').empty();
          result['data'].forEach((media)=>{
            $('#insert_options').append(
              $('<option>').attr('value', media['id']).text(media['name'])
            );
          });
          M.FormSelect.init($('#insert_options'));
          var instance = M.Modal.getInstance($('#insert_modal'));
          instance.open();
        }
      )
    }

    function insertMedia(name, id){
      var media = $('#insert_options').val();
      var mediaName = $('#insert_options :selected').text();
      $.post(
        '/instances/' + id + '/media',
        JSON.stringify({
          "source": media
        }),
        function(result){
          if (0 != result['error_code']) {
              M.toast({html: 'insert media fail: ' + result['message'], outDuration: 1000});
              return;
          }
          M.toast({html: 'media "' + mediaName + '" insert into ' + name });
        },
        "json"
      );
    }

    //eject media
    function confirmEject(name, id){
      $('#eject_confirm_content').text('Are you sure to eject media of guest ' + name);
      $('#eject_confirm_link').attr('onclick', 'ejectMedia("' + name + '", "' + id +'")');
      var instance = M.Modal.getInstance($('#eject_modal'));
      instance.open();
    }

    function ejectMedia(name, id) {
      $.ajax({
       url:'/instances/' + id + '/media',
       type: "DELETE",
       dataType: "json",
       data:JSON.stringify({
       }),
       success: function (result) {
           if (0 != result['error_code']) {
               M.toast({html: 'eject media fail: ' + result['message'], outDuration: 1000});
               return;
           }
           M.toast({html: 'media of guest "' + name + '" ejected'})
       }
      });
    }

    $(function(){
      M.Modal.init($('.modal'));
      if (parseQueryString()){
        $('#breadcrumb-path').append(
          $('<a>').addClass('breadcrumb').text(poolName).attr('href','cell_status.html?pool=' + poolName)
        );
        if (undefined != cellName){
          $('#breadcrumb-path').append(
            $('<a>').addClass('breadcrumb').text(cellName).attr('href','instance_status.html?pool=' + poolName + "&cell=" + cellName)
          );
        }
        $('#breadcrumb-path').append(
          $('<a>').addClass('breadcrumb').text(instanceID).attr('href','#')
        );

        initialCharts();
        updateDashboard();
        setInterval(updateDashboard, 2000);
      }
    });


  </script>
  </body>
</html>
